package zsl.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

public class NormalDistTable {
	
	public static class NormalDistPair implements Serializable{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		double x;
		double y;
		
		public NormalDistPair(double x, double y) {
			super();
			this.x = x;
			this.y = y;
		}
		
		@Override
		public String toString() {
			return "["+x+", "+y+"]";
		}
	}
	
	private static List<NormalDistPair> table = null;
	
	static{
		try {
			readTable();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
    
	private static void readTable() throws FileNotFoundException, IOException, ClassNotFoundException{
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("normalDistTable.out"));
		table = (List<NormalDistPair>) ois.readObject();
	}
	
	private static void generateTable() throws FileNotFoundException, IOException{
		ObjectOutputStream oop = new ObjectOutputStream(new FileOutputStream(new File("normalDistTable.out")));
		List<NormalDistPair> table = new ArrayList<>(400);
		fillTable(table);
		oop.writeObject(table);
		oop.close();
	}
	
	private static void fillTable(List<NormalDistPair> table){
		double x = 0;
		float step = 0.01f;
		while (x < 4) {
			table.add(new NormalDistPair(x, selfCaculate(x)));
			x += step;
		}
	}
	
	public static double getX(double y){
		if (y < 0.5) {
			throw new IllegalArgumentException("argument should larger than 0.5, but it is "+y);
		}
		int size = table.size();
		int i = 0;
		for (; i < size; i++) {
			if (table.get(i).y > y) {
				break;
			}
		}
		return Math.abs(table.get(i-1).y - y) <= Math.abs(table.get(i).y - y) ? table.get(i-1).x : table.get(i).x;
	}
	
	/**
     * 根据分割积分法来求得积分值
     * -3.89～3.89区间外的积分面积 小于 0.0001，
     * 所以确定有效的积分区间为-3.89～3.89
     * 在实现分割的时候精度定为0.0001，得到的结果和查表得到的结果误差在-0.0002～+0.0002之间（已经检验）
     * 
     * @param u      积分上限
     * @return       积分值
     */
    public static double selfCaculate(double u){
        double ret  = 0;

        if(u < -4){
            return 0;
        }
        else if(u > 4){
            return 1;
        }

        double temp = -8;
        while(temp <= u){
            ret += 0.000001f * fx(temp);

            temp += 0.000001f;
        }

        return ret;
    }

    /**
     * 求被积函数的函数值    (1/(2 * PI)^(0.5))e^(-t^2/2)
     * @param x      变量x
     * @return       函数值
     */
    private static double fx(double x){
        double ret = 0;

        double a = 1.0 / Math.sqrt(Math.PI * 2);

        a  = a * Math.pow(Math.E, -0.5 * Math.pow(x, 2));

        ret = a;

        return ret;
    }
    
    public static void main(String[] args) throws FileNotFoundException, IOException {
		double[] x = {0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.99};
		double[] x1 = new double[10];
		for (int i = 0; i < x1.length; i++) {
			x1[i] = x[i]+3;
		}
		
//		for (int i = 0; i < x1.length; i++) {
//			System.out.println((float)selfCaculate(x1[i]));
//		}
		
		System.out.println(table);
		System.out.println(getX(0.99));
		
    }

}
